package main

import (
	"fmt"
	"html/template"
	"io"
	"io/ioutil"
	"log"
	"net/http"
	"os"
	"path"
	"runtime/debug"
)

const (
	upload_path string = "./upload/"
	tpl_dir     string = "./views/"
)

var Tpls = make(map[string]*template.Template)

//初始化函数
func init() {
	//一次性加载模板目录下的文件
	allFile, err := ioutil.ReadDir(tpl_dir)
	check(err)
	for _, v := range allFile {
		file := v.Name()
		ext := path.Ext(file)
		if ext != ".html" {
			continue
		}
		t := template.Must(template.ParseFiles(tpl_dir + file))
		log.Println("加载模板", file)
		Tpls[file] = t
	}

}

//查看
func viewHandle(w http.ResponseWriter, r *http.Request) {
	//从表单之中获取参数
	imageId := r.FormValue("id")

	imagePath := upload_path + imageId
	if (imageId == "") || (false == isExist(imagePath)) {
		//http.NotFound(w, r) //设置404
		http.Error(w, "404", http.StatusNotFound) //同样设置404
		return
	}
	//设置http 响应头
	w.Header().Set("Content-type", "image")

	//返回请求的文件内容
	http.ServeFile(w, r, imagePath)
}

//列出 所有的文件
func listHandler(w http.ResponseWriter, r *http.Request) {
	//ioutil 这个包是 io 工具包 需要好好学习下
	fileInfos, err := ioutil.ReadDir(upload_path)
	check(err)

	//var listHtml string
	var localDatas = make(map[string]interface{})
	images := []string{}
	for _, fileInfo := range fileInfos {
		images = append(images, fileInfo.Name())

	}
	localDatas["images"] = images
	renderHtml(w, "list.html", localDatas)
}

//主页
func indexHandle(w http.ResponseWriter, r *http.Request) {
	renderHtml(w, "index.html", nil)
}

//上传
func uploadHandle(w http.ResponseWriter, r *http.Request) {
	//从请求当中判断方法
	if r.Method == "GET" {
		renderHtml(w, "upload.html", nil)
	} else {
		//获取文件内容 要这样获取
		file, head, err := r.FormFile("file")
		check(err)
		defer file.Close()
		//创建文件
		fW, err := os.Create(upload_path + head.Filename)
		check(err)
		defer fW.Close()
		_, err = io.Copy(fW, file)
		check(err)
		http.Redirect(w, r, "/list", http.StatusFound)
	}
}

/****渲染模板***/
func renderHtml(w http.ResponseWriter, tpl string, localDatas map[string]interface{}) {
	Tpls[tpl].Execute(w, localDatas)

}

/***处理错误***/
func check(err error) {
	if err != nil {
		panic(err)
	}
}

/**判断文件是否存在**/
func isExist(path string) bool {
	_, err := os.Stat(path)
	if err == nil {
		return true
	}

	return false
}

//d
func safeHandler(fn http.HandlerFunc) http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {
		defer func() {
			if e, ok := recover().(error); ok {
				http.Error(w, e.Error(), http.StatusInternalServerError)
				// 或者输出自定义的 50x 错误页面
				// w.WriteHeader(http.StatusInternalServerError)
				// renderHtml(w, "error", e)

				// logging
				log.Println("WARN: panic in %v - %v", fn, e)
				log.Println(string(debug.Stack()))
			}
		}()
		fn(w, r)
	}
}
func main() {
	//注册查看内容
	http.HandleFunc("/view", safeHandler(viewHandle))
	//上传
	http.HandleFunc("/image", safeHandler(uploadHandle))
	http.HandleFunc("/", safeHandler(indexHandle))
	//注册 展示
	http.HandleFunc("/list", safeHandler(listHandler))
	//启动一个http 服务器
	err := http.ListenAndServe(":8080", nil)
	if err != nil {
		fmt.Println("服务器启动失败")
		return
	}
	fmt.Println("服务器启动成功")
}
